接續昨天的管線:串接命令,今天主要紀錄
透過 Get-Command 先搜尋包含 JSON 的 command
PS /Users/kanglin/code/30day> get-command -Noun *json* | Format-Table -AutoSize
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertFrom-Json 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet ConvertTo-Json 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Test-Json 7.0.0.0 Microsoft.PowerShell.Utility
透過 Get-Help 確認 ConvertTo-Json 的用法
PS /Users/kanglin/code/30day> get-help ConvertTo-Json
NAME
ConvertTo-Json
SYNOPSIS
Converts an object to a JSON-formatted string.
SYNTAX
ConvertTo-Json [-InputObject] <System.Object> [-AsArray] [-Compress] [-Depth <System.Int32>] [-EnumsAsStrings] [-EscapeHandling <Newtonsoft.Json.StringEscapeHandling>] [<CommonParameters>]
第一層命令 Get-Item 讀取資料夾 30days。
PS /Users/kanglin/code/30days> Get-Item ../30days/
Directory: /Users/kanglin/code
UnixMode User Group LastWriteTime Size Name
-------- ---- ----- ------------- ---- ----
drwxr-xr-x kanglin staff 2024/9/21 11:22 64 30days
透過 pipeline 接第二層命令 ConvertTo-Json,將 Get-Item 的結果轉成 JSON 格式並呈現在終端機上。( 僅截圖部分 output )。
Get-Item ../30days/ | ConvertTo-Json | more
WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2.
{
"Name": "30days",
"Parent": {
"Name": "code",
"Parent": {
"Name": "kanglin",
"Parent": "/Users",
"Root": "/",
"Exists": true,
"FullName": "/Users/kanglin",
"Extension": "",
"CreationTime": "2023-09-17T22:22:28.1711557+08:00",
"CreationTimeUtc": "2023-09-17T14:22:28.1711557Z",
"LastAccessTime": "2024-09-21T11:26:39.6835802+08:00",
"LastAccessTimeUtc": "2024-09-21T03:26:39.6835802Z",
"LastWriteTime": "2024-09-21T11:26:39.6681179+08:00",
"LastWriteTimeUtc": "2024-09-21T03:26:39.6681179Z",
"LinkTarget": null,
"UnixFileMode": 488,
"Attributes": 16
},
"Root": {
"Name": "/",
"Parent": null,
"Root": "/",
"Exists": true,
"FullName": "/",
"Extension": "",
"CreationTime": "2024-08-04T18:31:41+08:00",
"CreationTimeUtc": "2024-08-04T10:31:41Z",
"LastAccessTime": "2024-08-04T18:31:41+08:00",
"LastAccessTimeUtc": "2024-08-04T10:31:41Z",
"LastWriteTime": "2024-08-04T18:31:41+08:00",
"LastWriteTimeUtc": "2024-08-04T10:31:41Z",
"LinkTarget": null,
"UnixFileMode": 493,
"Attributes": 17
},
"Exists": true,
"FullName": "/Users/kanglin/code",
"Extension": "",
再補上一個 pipeline 用第三個命令 Out-File 將剛剛第二層指令所產生的 JSON 格式內容存成 JSON file,在產生時,會跳 Warning 顯示物件內容因其巢狀屬性太多階層,超過第二層被截斷(預設到第二層)。
PS /Users/kanglin/code/30days> Get-Item ../30days/ | ConvertTo-Json | Out-File DisplayFolderPropertiesDepth2.json
WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2.
因為看到這樣的訊息,我就在想,到底可以到第幾層,因此透過 ConvertTo-Json 的參數去控制 Depth 的數值,到了第五層時,簡短的 Get-Item 指令居然可以產出近 53M 大小的 JSON file。所以我想除非任務上有需求,不然用 Default 的階層即可。
透過 Get-Help 確認 ConvertTo-Json 的用法
PS /Users/kanglin/code/30days> Get-Help ConvertFrom-Json
NAME
ConvertFrom-Json
SYNOPSIS
Converts a JSON-formatted string to a custom object or a hash table.
SYNTAX
ConvertFrom-Json [-InputObject] <System.String> [-AsHashtable] [-Depth <System.Int32>] [-NoEnumerate] [<CommonParameters>]
但是原先透過 Get-Item 所轉成的 Json file,再匯回物件時,所呈現出來的 table 並不是原先的格式,不過仔細看內容,可以發現原先的值是有被正確保存的,只是需要另外再做處理,這邊就不再往下延伸。
PS /Users/kanglin/code/30days> Get-Content ./DisplayFolderPropertiesDepth2.json | ConvertFrom-Json
透過 Get-Command 先搜尋包含 XML 的 command
PS /Users/kanglin/code/30days> get-command -Noun *xml* | Format-Table -AutoSize
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertTo-Xml 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Export-Clixml 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Import-Clixml 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Select-Xml 7.0.0.0 Microsoft.PowerShell.Utility
Export-Clixml 可以建立一個通用的 CLI XML 檔案,讓 PowerShell 可以重建原始物件(或是非常相近的物件)
何時使用 Export-Clixml
如果取得原始物件是更理想的結果,那為何不一直使用它呢?這裡有幾個缺點:
- 該格式往往更加龐大。
- 該格式是專為 PowerShell 設計的,在其他語言中可能解讀起來更為複雜。
- 在 Windows 上,PowerShell 會對檔案中與安全性相關的部分進行加密,這意味著只有建立該檔案的使用者或機器才能將它解密。
透過 Get-Help 確認 Export-Clixml 的用法
PS /Users/kanglin/code/30days> Get-Help Export-Clixml
NAME
Export-Clixml
SYNOPSIS
Creates an XML-based representation of an object or objects and stores it in a file.
SYNTAX
Export-Clixml [-Depth <System.Int32>] [-Encoding {ASCII | BigEndianUnicode | BigEndianUTF32 | OEM | Unicode | UTF7 | UTF8 | UTF8BOM | UTF8NoBOM | UTF32}] [-Force] -InputObject <System.Management.Automati
on.PSObject> -LiteralPath <System.String> [-NoClobber] [-Confirm] [-WhatIf] [<CommonParameters>]
Export-Clixml [-Path] <System.String> [-Depth <System.Int32>] [-Encoding {ASCII | BigEndianUnicode | BigEndianUTF32 | OEM | Unicode | UTF7 | UTF8 | UTF8BOM | UTF8NoBOM | UTF32}] [-Force] -InputObject <Sy
stem.Management.Automation.PSObject> [-NoClobber] [-Confirm] [-WhatIf] [<CommonParameters>]
透過 Get-Help 確認 Export-Clixml 的用法
PS /Users/kanglin/code/30days> Get-Help Import-Clixml
NAME
Import-Clixml
SYNOPSIS
Imports a CLIXML file and creates corresponding objects in PowerShell.
SYNTAX
Import-Clixml [-First <System.UInt64>] [-IncludeTotalCount] -LiteralPath <System.String[]> [-Skip <System.UInt64>] [<CommonParameters>]
Import-Clixml [-Path] <System.String[]> [-First <System.UInt64>] [-IncludeTotalCount] [-Skip <System.UInt64>] [<CommonParameters>]
PS /Users/kanglin/code/30days> Get-Help Import-Clixml -Examples | more
NAME
Import-Clixml
SYNOPSIS
Imports a CLIXML file and creates corresponding objects in PowerShell.
-- Example 1: Import a serialized file and recreate an object --
Get-Process | Export-Clixml -Path .\pi.xml
$Processes = Import-Clixml -Path .\pi.xml
剛剛有透過 Export-Clixm 將當下的 Process 紀錄起來(存成 XML),這裏依據書中的範例重新執行一次並將其取名為 ReferenceProcess.xml,所以等於我在 9/21 13:37 的時間點將 process 的 status 匯出成 clixml 檔案。
PS /Users/kanglin/code/30days> Get-Process | Export-Clixml ReferenceProcess
PS /Users/kanglin/code/30days> ls -lh | grep Process
-rw-r--r--@ 1 kanglin staff 3.5M 9 21 13:57 ReferenceProcess
透過 Get-Help 確認 Compare-Object 的用法
NAME
Compare-Object
SYNOPSIS
Compares two sets of objects.
SYNTAX
Compare-Object [-ReferenceObject] <System.Management.Automation.PSObject[]> [-DifferenceObject] <System.Management.Automation.PSObject[]> [-CaseSensitive] [-Culture <System.String>] [-ExcludeDifferent] [
-IncludeEqual] [-PassThru] [-Property <System.Object[]>] [-SyncWindow <System.Int32>] [<CommonParameters>]
接著便可透過 Compare-Object 的方式去比較目前的 Process 跟剛剛的 ReferenceProcess.xml 差異在哪
Compare-Object -ReferenceObject (Import-Clixml ./ReferenceProcess) -DifferenceObject (Get-Process) -Property Name
**Compare-Object**
:這個指令用來比較兩個物件(或集合)的不同之處。**-ReferenceObject**
:指定參考物件,也就是用來作為比較基準的物件。在這個例子中,是透過 Import-Clixml
指令從檔案 ./ReferenceProcess
匯入的內容。這個檔案預計包含之前系統的進程清單。**-DifferenceObject**
:指定需要與參考物件進行比較的物件。在這個例子中,使用 Get-Process
取得目前系統中所有正在執行的進程。**-Property Name**
:指定要比較的屬性。在這裡是根據進程的 Name
屬性(即進程名稱)進行比較。比較結果顯示在表格中,分為以下幾列:
**Name**
:顯示進程的名稱。**SideIndicator**
:指出進程的差異來源:
**=>**
表示這些進程存在於 ReferenceObject
(參考進程)中,但不存在於 DifferenceObject
(當前進程)中,代表這些進程已經結束或不再執行。**<=**
表示這些進程存在於 DifferenceObject
(當前進程)中,但不存在於 ReferenceObject
(參考進程)中,代表這些進程是新增的或現在正在執行。根據結果:
Google Chrome H =>
:表示 Google Chrome H
這個進程在參考進程中存在,但目前並未執行。Calendar <=
:表示 Calendar
這個進程目前正在執行,但在參考進程中沒有記錄到。mdworker\_shared =>
:表示多個 mdworker\_shared
進程在參考資料中存在但已不再執行。Code Helper <=
:表示多個 Code Helper
相關進程目前正在執行,但並不在原始參考中。書中有解釋到,當 cmdlet 執行後,顯示在終端機上的表格想要保存時,我們很常會使用
Dir > DirectoryList.txt
實際上,> 是被加進去 PowerShell 的一個捷徑,目的是為了提供與 Bash Shell 的相容性。實際上,當執行該指令時,PowerShell 在底層做了以下動作:
Dir | Out-File DirectoryList.txt
另外,PowerShell 中有各種以 Out- 開頭的 cmdlet,其中一個叫做 Out-Default,當你沒有特別指定其他以 Out- 開頭的 cmdlet 時,shell 預設會使用它,即使你沒有察覺,從技術上來講
Dir
# 你就是在執行
Dir | Out-Default
# 而 Out-Default 唯一做的事是將內容轉送給 Out-Host,因此實際上是在執行
Dir | Out-Default | Out-Host
# 最終,Out-Host 將資訊顯示在螢幕上
Day 8 - 擴充命令